//<SCRIPT>
function NestedPropListView ( listName, propList, itemLabel, configRootPath, serverMethod,
	sFormName, sListName, sEditName, aDirtyImgNames )
{

	if ( ! NestedPropListView.bIsInitialized )
		NestedPropListView.initClass();
	this.m_name = listName;
	this.m_itemLabel = itemLabel ;
	this.m_itemDefValue = itemLabel ;
	this.m_configRootPath = configRootPath;
	this.m_serverMethod = (serverMethod ? serverMethod : "servvar");
	this.m_propList = propList ;
	this.m_subListParent = this.m_propList;
	this.m_submitString = "";
	this.m_oWin = null;
	this.m_oDoc = null;
	this.m_sFormName = sFormName ;
	this.m_sListName = sListName ;
	this.m_sEditName = sEditName ;
	this.m_aDirtyImgNames = (aDirtyImgNames ? aDirtyImgNames : ["IMG_DIRTY_TAB", "IMG_DIRTY_APPLY"] );
	this.m_oES = null ;
	this.m_parent = null ;
	this.m_resultsTitleListIndex = 3;
	this.m_resultsTitlePropIndex = 4;
	this.m_curSubListName = "";
	this.m_origListChangeHandler = null;
	this.m_origClickHandler = null;
	this.m_origKeyUpHandler = null;
	this.m_bDoDirtyCheck = true ;
	this.m_imgSrcDirty = NestedPropListView.imgSrcDirty;
	this.m_imgSrcClean = NestedPropListView.imgSrcClean;
	this.m_hDirtyCheckTimerID = null;
	this.m_subViews = new Array();
	this.m_bLoaded = false;
}	// NestedPropListView ()
// class data
NestedPropListView.aDirtyImgNames = null;
NestedPropListView.imgSrcDirty = null;
NestedPropListView.imgSrcClean = null;
NestedPropListView.bIsInitialized = false;
NestedPropListView.InitClass = function ()
{
	// initialize class data
	NestedPropListView.aDirtyImgNames = ["IMG_DIRTY_TAB", "IMG_DIRTY_APPLY"];
	NestedPropListView.imgSrcDirty = new Image();
	NestedPropListView.imgSrcDirty.src = "images/arrow.gif" ;
	NestedPropListView.imgSrcClean = new Image();
	NestedPropListView.imgSrcClean.src = "images/spacer.gif" ;
	NestedPropListView.DIRTY_CHECK_SUPRESS_TIME = 1000 ;	//millisecs
	NestedPropListView.bIsInitialized = true;
}
NestedPropListView.prototype.addSubView = function ( subView )
{

	this.m_subViews[ subView.m_name ] = subView ;
	subView.m_parent = this ;
	// a sub view shouldn't do dirty checks - presumably the parent does 'em
	subView.m_bDoDirtyCheck = false ;
}	// addSubView ()
NestedPropListView.prototype.toString = function ()
{
	return this.m_name ;
}
NestedPropListView.prototype.subView = function ( subViewName )
{
	return this.m_subViews[ subViewName ];
}
NestedPropListView.prototype.formName = function ( sFormName )
{
	if ( sFormName )
	{
		this.m_sFormName = sFormName ;
	}
	return this.m_sFormName ;
}
NestedPropListView.prototype.getForm = function ( subListName )
{
	return getElem( this.m_sFormName );
}
NestedPropListView.prototype.getListCtrl = function ()
{
	var oForm = getElem( this.m_sFormName );

	if ( oForm )
	{

		return oForm[ this.m_sListName ];
	}
	return null ;
}
NestedPropListView.prototype.getEditCtrl = function ()
{
	var oForm = getElem( this.m_sFormName );

	if ( oForm )
	{

		return oForm[ this.m_sEditName ];
	}
	return null ;
}
NestedPropListView.prototype.preOnLoad = function ()
{
	return true ; // continue with super class onLoad
}
/* 
	before calling this function make sure the propList member has been initialized.
	Call this method from your pages onload handler, passing in the
	following page element/obj references:
		oWin		the page's window object, required
	after using the parameters to initialize the object's member properties, onPrelLoad is called. This allows
	subclasses to perform any need initialization. The base class's implementation jsut returns true, if an 
	subclass's onPreLoad returns false the bodyof onLoad is skipped.
	The bodyof this method initializes the form using propList data as well as creating an EditSelect obj
	to tie the list and edit controls together.
	onPostLoad is then called at the end. A do nothing method in the base class onPostLoad should be overridden
	in sub classes to perform custom actions - hide/show/resize elements etc.
*/
NestedPropListView.prototype.onLoad = function ( oWin, fNoInitForm, fNoDisplayData )
{

	// initialize member variables TODO validate parameters	
	if (! oWin ) return;
	if ( ! isXblibInit ) xblibInit();
	this.m_oWin = oWin;
	this.m_oDoc = oWin.document;
	this.m_bLoaded = true ;
	if ( this.preOnLoad() )
	{
		this.m_propList.reset();
		if( this.m_bDoDirtyCheck )
			this.showDirtyFlag( false );
		if ( ! fNoInitForm )
			clearForm( this.getForm() );
		// create or (if in reset mode) sync the EditSelct object
		if ( ! this.m_oES )
		{	
			this.m_oES = new EditSelect2( this.m_oWin, this.getListCtrl(), this.getEditCtrl(), this );
			this.m_oES.itemName( this.m_itemLabel );
		}
		//init any subViews
		for ( var subViewName in this.m_subViews )
		{
			var subView = this.m_subViews[ subViewName ];
			if ( subView )
			{
				subView.onLoad( oWin, true, true );
			}
		}
		if ( ! fNoDisplayData )
		{
			this.initListDataDisplay();
		}
		if ( ! fNoInitForm )
			this.hookForm();
	}
	this.postOnLoad();
}	// onLoad()
NestedPropListView.prototype.initListDataDisplay = function ()
{
	this.m_oES.clear();
	this.fillSelectList();
	this.m_oES.sync();
	this.m_propList.fillForm( this.getForm() );
	this.fillFormFromSubList( false );
}
NestedPropListView.prototype.postOnLoad = function ()
{
	// no return value needed
}
NestedPropListView.prototype.fillSelectList = function ()
{
	if ( ! this.m_bLoaded ) return ;

	var listCtrl = this.getListCtrl();
	if ( listCtrl )
	{
		listCtrl.options.length = 0;
		// fill the list with the name of each sublist
		this.m_subListParent.fillSelectList( listCtrl );
		// and select the first one
		selectFirst( listCtrl );
	}
}	// fillSelectList ()
NestedPropListView.prototype.onESSelChange = function ( oES )
{
	if ( ! this.m_bLoaded ) return ;
	return this.fillFormFromSubList( true );
}	// onESSelChange ()
NestedPropListView.prototype.fillFormFromSubList = function ( fValidate )
{
	if ( ! this.m_bLoaded ) return ;
	var newSubListName = this.m_oES.getItemValue();
	if ( ! newSubListName )
	{
		if ( this.m_oES.count() == 0 )
		{
			this.m_curSubListName = "" ;

			return true ;
		}
		var listCtrl = this.getListCtrl();
		if ( listCtrl )
		    listCtrl.selectedIndex = 0;
		newSubListName = this.m_oES.getItemValue();
	}
	// before filling in the controls with the newly selected sublist's value's
	// validate and store chgs for the current (or old) sublist
	if ( this.m_curSubListName && fValidate && ( ! this.validateSubList() ) )
	{
		// the ES control will go back to the last selection if we return false
		return false ;
	}
	if ( ! newSubListName ) return false ;

	this.m_curSubListName = newSubListName ;
	var subList = this.getSubList( newSubListName );
	if ( subList )
	{
		subList.fillForm( this.getForm( newSubListName ) );
		//set the propList and fill the select list of any subViews
		for ( var subViewName in this.m_subViews )
		{
			var subView = this.m_subViews[ subViewName ];
			if ( subView && subView.m_bLoaded )
			{
				var subSubList = subList.subList( subViewName );
				if ( subSubList )
				{
					subView.setPropList( subSubList );
					subView.initListDataDisplay();
				} 
			}
		}
	}
	return this.postFillFormFromSubList( fValidate );
}	// fillFormFromSubList ()
NestedPropListView.prototype.setPropList = function ( propList, subListParentName )
{
	this.m_propList = propList ;
	if ( (!isBlank( subListParentName )) && 
		 propList.subList( subListParentName ) )
	{
		this.propList = propList;
		this.m_subListParent = propList.subList( subListParentName );
	}
	else
	{
		this.propList = this.m_subListParent = propList ;
	}
}	// setPropList
NestedPropListView.prototype.postFillFormFromSubList = function ( fValidate )
{
	return true;
}
NestedPropListView.prototype.preValidateSubList = function ( subListName )
{
	return true;
}
NestedPropListView.prototype.validateSubList = function ( subListName )
{
	if ( ! this.m_bLoaded ) return ;
	if ( isBlank( subListName ) )
	{
		if ( ! this.m_oES.doRenameCheck() )
		{
			//alert( "failed renamecheck");
			return false ;
		}
		subListName = this.m_curSubListName ;
	}

	if ( ! this.preValidateSubList( subListName ) )
	{

		return false ;
	}
	var subList = this.m_subListParent.subList( subListName );
	if ( subList )
	{
		var ctrl = subList.validate( this.getForm( subListName ) );
		if ( ctrl ) 
		{
			return rejectInput( ctrl, subList.errMsg );
		}
	}
	//validate any subViews
	for ( var subViewName in this.m_subViews )
	{
		var subView = this.m_subViews[ subViewName ];
		if ( subView && subView.m_bLoaded )
		{
			if ( ! subView.validateSubList() )
				return false ;
		}
	}
	if ( ! this.postValidateSubList( subListName ) )
	{

		return false ;
	}
	return true ;
}	// validateSubList ()
NestedPropListView.prototype.getSubList = function ( subListName )
{
	if ( isBlank( subListName ) )
	{
		subListName = this.m_curSubListName ;
	}
	return this.m_subListParent.subList( subListName );
}
NestedPropListView.prototype.postValidateSubList = function ( subListName )
{
	return true;
}
NestedPropListView.prototype.preValidate = function ()
{
	return true;
}
/* ------------ validate the form and create the submit string --------------*/
NestedPropListView.prototype.validate = function ( fNoSubmitString, fNoAlert )
{
	if ( ! this.m_bLoaded ) return ;

	this.m_submitString = "" ;
	if ( ! this.preValidate() )
	{

		return false ;
	}
	var ctrl = this.m_propList.validate( this.getForm() );
	if ( ctrl ) 
	{

		return rejectInput( ctrl, this.m_propList.errMsg );
	}
	// validate and save the subLists
	var subList, ctrl ;
	if ( this.m_curSubListName &&
		 (! this.validateSubList() ) )
	{

		return false ;
	}
	if ( ! fNoSubmitString )
		this.buildParamString();
	if ( ! this.postValidate() )
	{

		return false ;
	}
	// chk for unchanged condition
	if ( (!fNoSubmitString) && (!this.m_submitString) )
	{
		if ( ! fNoAlert )
		{
			alert( "没有更改" + this.m_name + " 的设置." );
		}
		return false ;
	}

	return true ;
}	// validate ()
NestedPropListView.prototype.postValidate = function ()
{
	return true;
}
NestedPropListView.prototype.buildParamString = function ()
{
	if ( ! this.m_bLoaded ) return ;

	function _getInstanceOf_buildParamStringCallback ( obj )
	{
		return function( propList, prop, paramStr )
		{
			return obj.buildParamStringCallback( propList, prop, paramStr );		
		}
	}
	this.m_submitString = this.m_propList.buildParamString( 
		this.m_configRootPath, false, _getInstanceOf_buildParamStringCallback( this ) );
}	// buildParamString ()
NestedPropListView.prototype.buildParamStringCallback = function ( propList, prop, paramStr )
{
	return paramStr ;
}
NestedPropListView.prototype.doSubmit = function ()
{
	if ( ! this.m_bLoaded ) return ;
	function _getInstanceOf_resultsCallback ( obj )
	{
		return function(results)
		{
			return obj.resultsCallback(results);		
		}
	}
	var method = (this.m_serverMethod == 
		"servvar" ? (this.m_propList.needRestart() ? "configvar" : "servvar") : this.m_serverMethod);
	var winResults = raSubmitChanges( method, this.m_submitString, 
		this.m_name + " Settings", _getInstanceOf_resultsCallback( this ) );
	commitForm( this.getForm() );
	this.m_propList.commit();
	this.fillFormFromSubList( false );
	if ( winResults && (!winResults.closed) )
	{
		winResults.focus();
	}
	if( this.m_bDoDirtyCheck )
		this.showDirtyFlag( false );
	this.postSubmit();
}	// doSubmit ()
NestedPropListView.prototype.postSubmit = function ()
{
}	// postSubmit
NestedPropListView.prototype.resultsCallback = function ( results )
{
	// TODO use members to determine the properties to print
	// use the fourth and fifth properties as the result title
	var res, a;
    for (var i = 0; i < results.length; i++)
    {
		res = results[i];
		a = res.prop.split( "." );
		if ( a[ this.m_resultsTitlePropIndex ] )
		{
        	res.title = a[ this.m_resultsTitleListIndex ].ent().span("body") + '<br>' + 
        	a[ this.m_resultsTitlePropIndex ];
		}
		else if ( a[ this.m_resultsTitleListIndex ] )
		{
        	res.title = a[ this.m_resultsTitleListIndex ].ent().span("body");
		}
	}
}
NestedPropListView.prototype.hookForm = function ()
{
	if ( ! this.m_bLoaded ) return ;
	if( this.m_bDoDirtyCheck )
	{
		//because of Mozilla Bug 49980 (as of 4/11/01) we can't use anonymous functions
		//as event handlers - so we assign the instance method call generated by
		// getInstanceEventHandler() to a variable of TOC window...
		this.m_oWin._onDocClick = getInstanceEventHandler( this, "onFormKeyOrClick" );
		//... and then hook it in as the document's click handler
		this.m_origClickHandler = addEvent( this.m_oDoc, "click", 
			this.m_oWin._onDocClick, 1, "Event.CLICK" );
		// ...do the same for the keyup event
		this.m_oWin._onDocKeyUp = getInstanceEventHandler( this, "onFormKeyOrClick" );
		this.m_origKeyUpHandler = addEvent( this.m_oDoc, "keyup", 
			this.m_oWin._onDocKeyUp, 1, "Event.KEYUP" );
		// ...set up the timeout handler
		this.m_oWin._doDirtyChk = getInstanceEventHandler( this, "doDirtyChk" );
	}
}	// hookForm ()
NestedPropListView.prototype.onFormKeyOrClick = function ( evt )
{
	if ( ! this.m_bLoaded ) return ;
	// if we've already set the time then ignore
	if ( this.m_bDoDirtyCheck && (!this.m_hDirtyCheckTimerID) )
	{
		var oForm = this.getForm();
		// if the event src element is not part of our form then ignore
		var srcElem = ( isIE ? this.m_oWin.event.srcElement : evt.target );
		if ( (srcElem.form && (srcElem.form == oForm)) ||
			 (oForm == getParentByTagName( srcElem, "FORM" )) )
		{

			this.m_hDirtyCheckTimerID = this.m_oWin.setTimeout( "_doDirtyChk()", NestedPropListView.DIRTY_CHECK_SUPRESS_TIME );
		}
	}

	var evtType = ( evt ? evt.type : this.m_oWin.event.type );
	if ( this.m_origClickHandler && (evtType == "click") )
	{
		return this.m_origClickHandler( evt );
	}
	else if ( this.m_origKeyUpHandler )
	{
		return this.m_origKeyUpHandler( evt );
	}
	if ( isNav4 )
	  	this.m_oDoc.routeEvent( evt );
	return true ;
}	// onFormKeyOrClick
NestedPropListView.prototype.doDirtyChk = function ()
{
	if ( ! this.m_bLoaded ) return ;
	if ( this.m_bDoDirtyCheck )
	{
		this.showDirtyFlag( this.isDirty() );
		this.m_hDirtyCheckTimerID = null ;
	}
}
NestedPropListView.prototype.isDirty = function ()
{
	if ( ! this.m_bLoaded ) return ;

	if ( this.m_bDoDirtyCheck ) 
	{
		if ( this.m_propList.isFormDirty( this.getForm(), 1 ) )
		{
			return true ;
		}
		var subList = this.getSubList();
		if ( subList && subList.isFormDirty( this.getForm() ) )
		{
			return true ;
		}
		if ( this.m_propList.isDirty() )
		{
			return true ;
		}
		return this.postIsDirty();
	}
	return false;
}
NestedPropListView.prototype.postIsDirty = function ()
{
	return false ;
}
NestedPropListView.prototype.showDirtyFlag = function ( bIsFormDirty )
{
	if ( ! this.m_bLoaded ) return ;
	if ( this.m_bDoDirtyCheck )
	{
		for ( var i = 0; i < this.m_aDirtyImgNames.length; i++ )
		{
			var oImgDirty = getElem( this.m_aDirtyImgNames[ i ] );
			if ( oImgDirty )
			{
				oImgDirty.src = 
				(bIsFormDirty ? 
					this.m_imgSrcDirty.src : 
					this.m_imgSrcClean.src);
			}
		}
	}
}
// *******  ADD / EDIT / REMOVE / COPY SUBLIST FUNCTIONS ********
// notify functions - override in sub classes if need be
NestedPropListView.prototype.onSubListChangeNotify = function ( action, subListName )
{
	if ( ! this.m_bLoaded ) return ;
	if ( this.m_bDoDirtyCheck )
		this.showDirtyFlag( this.isDirty() );
}
NestedPropListView.prototype.confirmRenameSubList = function ( oldSubListName, newSubListName )
{
	// by default, a rename is OK
    return true ;
}	// confirmRenameSubList ()
NestedPropListView.prototype.onESRename = function ( oldSubListName, newSubListName )
{
	if ( ! this.m_bLoaded ) return ;

	// validate the newTestName
	if ( ! this.m_propList.listname_validate( newSubListName ) )
	{
		return rejectInput( this.getEditCtrl(), this.m_propList.errMsg );
	}
	if ( ! this.confirmRenameSubList( oldSubListName, newSubListName ) )
	{
		return false ;
	}
	this.m_subListParent.renameSubList( oldSubListName, newSubListName );
	this.m_curSubListName = newSubListName ;
	this.onSubListChangeNotify( "rename", oldSubListName, newSubListName );
	return true ;
}	// onESRename ()
// called when the select control is empty and the user types into 
// the edit control - create a new sublist with the entered text as the
// sublist name
NestedPropListView.prototype.onESAddNew = function ( oES )
{
	if ( ! this.m_bLoaded ) return ;
	var subListName = oES.getEditText();

	if ( subListName ) 
	{
		this.createSubList( subListName );
	}
}	// onESAddNew ()
NestedPropListView.prototype.createSubList = function ( subListName )
{
	if ( ! this.m_bLoaded ) return ;
	// validate and save the current list's values
	if ( this.m_curSubListName && ( ! this.validateSubList() ) ) 
	{
		return ;
	}
	if ( subListName )
	{
		this.m_oES.addOption( subListName, subListName, true );
	}
	else
	{
		if ( ! this.m_itemDefValuePostFix )
			subListName = this.m_oES.addUntitled( this.m_itemDefValue );
		else
			subListName = this.m_oES.addUntitled( this.m_itemDefValue, 0, 
				this.m_itemDefValuePostFix );
	}

    if ( subListName )
	{
		this.m_curSubListName = subListName;
		var subList = new PropList( subListName, [], this.m_subListParent.m_propSetSubLists );
		this.m_subListParent.addSubList( subList, "added" );
		subList.clearForm( this.getForm( subListName ) );
		this.fillFormFromSubList( false );
		var editCtrl = this.getEditCtrl();
		if ( editCtrl )
		{
			editCtrl.focus();
			editCtrl.select();
		}
		this.onSubListChangeNotify( "add", subListName );
	}
}	// createSubList ()
NestedPropListView.prototype.copySubList = function ()
{
	if ( ! this.m_bLoaded ) return ;
	if ( ! this.m_curSubListName )
	{
		/*alert( "选择 " + this.m_name + " 进行拷贝" );*/
		return ;
	}
	// validate and save the current list's values
	if ( this.m_curSubListName && ( ! this.validateSubList() ) ) 
	{
		return ;
	}
	var newSubListName = this.m_oES.addUntitled( "Copy", 0, " of " + this.m_curSubListName );
    if ( newSubListName )
	{
		this.m_subListParent.copySubList( this.m_curSubListName, newSubListName );
		this.m_curSubListName = newSubListName;
		this.fillFormFromSubList( false );
		var editCtrl = this.getEditCtrl();
		if ( editCtrl )
		{
			editCtrl.focus();
			editCtrl.select();
		}
		this.onSubListChangeNotify( "add", newSubListName );
	}
 }	// copySubList ()
NestedPropListView.prototype.resetSubList = function ()
{
	if ( ! this.m_bLoaded ) return ;

	if ( ! this.m_curSubListName )
	{
		/*alert( "选择一个 " + this.m_name + " 进行重置." );*/
		return;
	}
	var subList = this.m_subListParent.subList( this.m_curSubListName );
	if ( subList )
	{
		subList.resetToDefaults( this.getForm( this.m_curSubListName ) );
	}
	if ( this.m_bDoDirtyCheck )
		this.showDirtyFlag( this.isDirty() );
}	// resetSubList
NestedPropListView.prototype.removeSubList = function ()
{
	if ( ! this.m_bLoaded ) return ;
	if ( ! this.m_curSubListName )
	{

		return;
	}
	// in case the sublist was renamed
	if ( ! this.m_oES.doRenameCheck() )
		return ;

	var subList = this.getSubList();
	if ( subList )
	{
	    if ( this.confirmRemoveSubList( this.m_curSubListName ) )
		{
			var deletedSubListName = this.m_curSubListName;
			// mark as 'deleted'
			this.m_oES.remove();
			subList.clearForm( this.getForm( deletedSubListName ) );
			if ( subList.m_status == "added" )
			{
				this.m_subListParent.delSubList( subList );
			}
			else
			{
				subList.m_status = "deleted" ;
			}
			this.onSubListChangeNotify( "delete", deletedSubListName );
			this.fillFormFromSubList( false );
		}
	}
}	// removeSubList ()
NestedPropListView.prototype.confirmRemoveSubList = function ( subListName )
{
    return confirm( "删除 " + this.m_itemLabel + " '" + subListName + "'?" );
}	// confirmRemoveSubList ()
/*if ( isIE )
{
	window.onbeforeunload = onBeforeUnload ;
}
else
{
	window.onunload = onUnload ;
}
*/
/*
function onBeforeUnload ()
{
}
function onUnload ()
{
	if ( (null != isFormDirty( theForm )) || propList.isDirty() )
	{
		if ( confirm (
				"你所做的仅用于测试的改变,将不会被保存.\n\n" +
				"- 按确定按钮来保存你的改变.\n" +
				"- 按取消按钮来放弃你所做的改变." ) )
		{
			saveTest();
		}
	}
}
function saveTest ()
{
	validate();
	if ( submitString )
		doSubmit();
}
*/
NestedPropListView.InitClass();
//</SCRIPT>

